package de.micromata.cal;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.text.SimpleDateFormat;
import java.util.LinkedList;
import java.util.Locale;

import net.fortuna.ical4j.filter.Filter;
import net.fortuna.ical4j.filter.PeriodRule;
import net.fortuna.ical4j.model.Calendar;
import net.fortuna.ical4j.model.Component;
import net.fortuna.ical4j.model.ComponentList;
import net.fortuna.ical4j.model.DateTime;
import net.fortuna.ical4j.model.Dur;
import net.fortuna.ical4j.model.Period;
import net.fortuna.ical4j.model.Property;
import net.fortuna.ical4j.model.component.VEvent;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

/*
 * Settings for Kodak Digital Frame W820
 * 800 x 480 pixel
 * 
 * + + + + + + + + + + + + +
 * digital frame overview  +
 * + + + + + + + + + + + + +
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 																					# # # # # # # # #			 *
 * 		1.																		#		 L O G O		# 		 *
 * 		<Weekday-Name>, DD MM YY							#	  part of the	#		 	*
 * 		 																			# 	 template		#			 *
 * 					2. HH : MM											# # # # # # # # #			 *
 * 																																 *
 * 																																 *
 * 				4.																									6.	 *
 *<------------------> 							5. (auto)								<----->*
 * 	  3.							<------------------------------------>			 *
 * 		09:30 - 11:00		Meeting 1																		 *
 * 																																 *
 * 		12:00 - 14:00		Meeting 2																		 *
 * 										John Doe, Jack Bauer												 *
 * 																																 *
 * 		16:30 - 17:00		Meeting 3																		 *
 * 															   8. ^														 *
 * 																		|														 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 
 * + + + + + + + + + +
 * line height view  +
 * + + + + + + + + + +
 *		09:30	- 11:00		Meeting 1
 *		^
 *		| 8.
 *		12:00	- 14:00 	Meeting 2
 *										| 9.
 *										John Doe, Jack Bauer
 * 
 * 
 * 
 */

public class Drawing {
	
	private static Logger LOG = Logger.getRootLogger();
	private static SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm", Locale.GERMAN);
	private static SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE, dd.MM.yy", Locale.GERMAN);
	private static SimpleDateFormat dateAndMonthFormat = new SimpleDateFormat("dd.MM.", Locale.GERMAN);
	
	private static int width = 800;
	private static int height = 480;
	
	private static Point datePosition = new Point(110, 50); // 1.
	private static Point timePosition = new Point(220, 100); // 2.
	private static Point contentStartPosition = new Point(100, 200); // 3.
	private static int timeAndDescriptionSpace = 190; // 4.
	private static int rightPadding = 110; // 6.
	
	// 5) 
	// 					width - 3.x - 4 - right padding
	// example: 800 - 100 -   190 - 110  = 400
	private static int maxContentDescriptionWidth = width - (int)contentStartPosition.getX() - timeAndDescriptionSpace - rightPadding; 
	
	//drawing start positions

	static int bottomPadding = 10; // 8.
	static int leftPadding = contentStartPosition.x;
	static int descriptionPadding = leftPadding + timeAndDescriptionSpace;
	
	//define font styles
	private static Font eventDescriptionFont =  new Font("Arial", Font.PLAIN, 30);
	private static Font eventTimeFont = eventDescriptionFont.deriveFont(Font.BOLD, 30);
	private static Font timeFont = eventDescriptionFont.deriveFont(Font.BOLD, 45);
	private static Font longDateFont = eventDescriptionFont.deriveFont(Font.BOLD, 36); 
	private static int fontSize = Math.max(eventDescriptionFont.getSize(), eventTimeFont.getSize()); 
	private static int lineHeight = fontSize + 5; // 7. not less than the fonz size
	private static int lineHeightSpace = 10; // 8. space between the events
	
public static void drawContent(BufferedImage bufferImg, Calendar calendar) {
	
	int topPadding = contentStartPosition.y;
	java.util.Calendar now = java.util.Calendar.getInstance(); // current time
	
// create a calendar object for the current day
int remainingHoursToday = 24 - now.get(java.util.Calendar.HOUR_OF_DAY) + 1;

// create a period until the end of the current day
Period period = new Period(new DateTime(now.getTime()), new Dur(0, remainingHoursToday, 0, 0));
Filter filter = new Filter(new PeriodRule(period));


// filter only events, which start today
ComponentList todayList = (ComponentList) filter.filter(calendar.getComponents(Component.VEVENT));
todayList = Utils.sortEvents(todayList);
LOG.debug(todayList.size() + " events was found");

// get Graphics2D to use draw commands
Graphics2D g2d = bufferImg.createGraphics();
// set anti aliasing for geometry and text
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.WHITE);

// draw date
g2d.setFont(longDateFont);
g2d.drawString(""+dateFormat.format(now.getTime()), datePosition.x, datePosition.y);
// draw time
g2d.setFont(timeFont);
g2d.drawString(""+timeFormat.format(now.getTime()), timePosition.x, timePosition.y);

// drawing content
for (Object e : todayList) {
  VEvent event = (VEvent) e;
  LOG.debug("found event:\n"+event.getSummary());
  
  // get start and end time of the current event
  java.util.Calendar eventStart = java.util.Calendar.getInstance();
  java.util.Calendar eventEnd = java.util.Calendar.getInstance();
  eventStart.clear();
  eventEnd.clear();
  eventStart.setTime(event.getStartDate().getDate());
  eventEnd.setTime(event.getEndDate().getDate());
  
  String eventTime = timeFormat.format(eventStart.getTime()) + " - " + timeFormat.format(eventEnd.getTime());
  
  // set font to calculate the multiLines
  g2d.setFont(eventDescriptionFont);
  String summary = event.getSummary().getValue(); // get the description/summary
  
  if (eventStart.get(java.util.Calendar.DAY_OF_MONTH) != eventEnd.get(java.util.Calendar.DAY_OF_MONTH)) {
  	String dateAndMonth = "/(" + dateAndMonthFormat.format(eventStart.getTime()) + " - " + dateAndMonthFormat.format(eventEnd.getTime()) + ")";
  	summary += dateAndMonth;
  }
  
  // break the text: summary with the current Font, if the width is more than maxContentDescriptionWidth
  LinkedList<String> multiLines = Utils.breakText(g2d.getFontMetrics(), summary, maxContentDescriptionWidth);
  int lineCount = 0;
  // check if the summaray fit into the space (it will only display 3 lines max.)
  int nextTopPaddingPosition = (Math.min(multiLines.size(), 3)-1) * lineHeight + topPadding;
  if (nextTopPaddingPosition >= (height - bottomPadding)) {
    LOG.info("event summaray position is out of bounds: "+nextTopPaddingPosition);
    break;
  }
  // draw event time
  g2d.setFont(eventTimeFont);
  g2d.drawString(eventTime, leftPadding, topPadding);
  
  g2d.setFont(eventDescriptionFont);

  for (String line : multiLines) {
    lineCount++;
    // if the text have more than 3 lines, cut the last word of the 3th line and print "..."
    if (lineCount == 3 && multiLines.size() > 3) {
      String[] words = line.split(" ");
      ArrayUtils.remove(words, words.length-1); // remove last word
      line = StringUtils.join(words, ' ') + " ..."; // join words and append "..."
      // draw summary
      g2d.drawString(line, descriptionPadding, topPadding); 
      topPadding += lineHeight;
      break;
    // if the text don't have more than 3 lines
    } else {
      LOG.info("drawing: "+descriptionPadding+" , "+topPadding+": "+line);
      g2d.drawString(line, descriptionPadding, topPadding); // print summary
      topPadding += lineHeight;
    }
  }
  
  // check if the current event take place right now and draw a rounded rectangle around the event
  boolean frequentlyEvents = false;
  // special check for frequently events, which have a RRULE property
  if (event.getProperty(Property.RRULE) != null) {
    // the frequently events have the wrong date, for comparing them with the current time
    // create new calendar objects with the current date and the time of the event
    java.util.Calendar finishEvent = (java.util.Calendar)now.clone();
    java.util.Calendar beginEvent = (java.util.Calendar)now.clone();
    finishEvent.set( java.util.Calendar.HOUR_OF_DAY, eventEnd.get(java.util.Calendar.HOUR_OF_DAY));
    finishEvent.set( java.util.Calendar.MINUTE, eventEnd.get(java.util.Calendar.MINUTE));
    beginEvent.set( java.util.Calendar.HOUR_OF_DAY, eventStart.get(java.util.Calendar.HOUR_OF_DAY));
    beginEvent.set( java.util.Calendar.MINUTE, eventStart.get(java.util.Calendar.MINUTE));
    
    // filter only events, which taking place right now
    if (now.after(beginEvent)) {
      Period period2 = new Period(new DateTime(now.getTime()), new DateTime(finishEvent.getTime()));
      Filter filter2 = new Filter(new PeriodRule(period2));
      ComponentList nowList = (ComponentList) filter2.filter(calendar.getComponents(Component.VEVENT));
      frequentlyEvents = !nowList.isEmpty();
    }
  }
  
  boolean notFrequentlyEvents = now.after(eventStart) && now.before(eventEnd);
  if (notFrequentlyEvents || frequentlyEvents)  {
    int roundedCorner = 50;
    int descender = (int) (fontSize * 0.25); // wihtout that space, the bottom of the rectangle would draw under the baseline of the text
    // draw around the time and the summary
    RoundRectangle2D r2 = new RoundRectangle2D.Double(
        leftPadding-10, contentStartPosition.y-fontSize, 
        width-((leftPadding+rightPadding)-35), (lineHeight/2+((lineCount-1)*lineHeight)+descender+lineHeight/2), 
        roundedCorner, roundedCorner);
    g2d.setStroke(new BasicStroke(3));
    g2d.draw(r2);
  }
  
  topPadding += lineHeightSpace; // space for next event
  if (topPadding >= (height - bottomPadding)) {
    LOG.info("bottomPadding overflow, no more events will draw");
    // draw no more events, because there is not enough space anymore
    break;
  }
}
g2d.dispose(); // release resource
  
}
}
